//
//  GPSReadyViewController.swift
//  DaFit
//
//  Created by Paul on 2021/12/16.
//  Copyright © 2021 sylar. All rights reserved.
//

import UIKit
import MapKit
import CoreLocation
import SQLite
import RxSwift
import MYModule
import CRPSmartRing


open class GPSTrainingMapViewController: ViewController, MKMapViewDelegate, CLLocationManagerDelegate, GoalSettingResponseDelegate {
    
    // 水平精度
    public let GPSHorizontalAccuracy: Double = 20.0
    
    //GPS信号区间
    public let GPSSignalLevel1: Double = 100
    public let GPSSignalLevel2: Double = 20
    public let GPSSignalLevel3: Double = 10
    public let GPSSignalLevel4: Double = 5
    
    /// 当前界面是在运动中/未开始/暂停
//    var trainingState: CRPTrainingState = .exercising
    
    public var type: TrainingType = .unknown
    public var mapView: MKMapView = MKMapView(frame: CGRect.zero)
    public var gpsButton: UIButton!
    public var countDownView: CountDownLabel!
    public var countDownBGView: UIView!
    
    public var gpsGoalType: TrainingTypeContent = .unkown
    
    public var gpsGoal: Double = 0
    
    public var pastSteps: Int = 0
    public var pastDistance: Double = 0.0
    
    // 获取最后一个detail的数据
    public var startDetail = ActivityModel()
    
    public var LMLocal:CLLocation?
    public var MapLocal:CLLocation?
    public var isChina: Bool = false
    public var currentEnableLocation: Bool = false
    
    public let locationManager:CLLocationManager = CLLocationManager()
    
    public var userAnnotationView: MKAnnotationView?
    
    open var barViewHidden: Bool = false{
        didSet{
            self.navigation.bar.isHidden = barViewHidden
        }
    }
    
    public let gpsSignalView = GPSSignalView(frame: CGRect(x: 0, y: 0, width: 100, height: 24))
    
    public let infoView = GPSTrainingMapInfoView()
    
    public var infoModel = GPSTrainingInfoModel(type: .unkown)
    
    public let willStartView = GPSWillStartView()
    
    //Data
    public var coordinateArray: [CLLocationCoordinate2D] = []
    
    public var gpsTrainModel: GPSTrainingModel?
    
    public var runTime: Int = 0
    public var time: Timer?
    open var gpsAccuracy = 0.00 {
        didSet{
            setGPSSignal()
        }
    }
//
//    var stopCal: Int64 = 0
//    var stopStep: Int64 = 0
    
    /// 是否断连
    public var isDisconnected: Bool = false
    
    
    open override func viewDidLoad() {
        super.viewDidLoad()
        
        navigationBar()
        
        if let startDetail = ActivityModel.day(date: Date()) {
            self.startDetail = startDetail
        }
        
        // 卡路里显示
        if let gpsTrainModel = gpsTrainModel, gpsTrainModel.trainingState != 0 {
            infoModel.updateData(type: .calorie, currentData: Double(gpsTrainModel.kcal))
            if gpsTrainModel.locations.count > 0 {
                var clLocations = [CLLocationCoordinate2D]()
                for dbLocation in gpsTrainModel.locations {
                    if let location = dbLocation.clLocation {
                        clLocations.append(location.coordinate)
                    }
                }
                self.coordinateArray.insert(contentsOf: clLocations, at: 0)
                updatePath()
            }
        }
    }
    
    open override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.navigation.bar.barStyle = .black
        NotificationCenter.default.addObserver(self, selector: #selector(updateUI(noti:)), name: .kUpdateUINotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(deviceStateChange(noti:)), name: .kDeviceStateNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(bluetoothStateChange(noti:)), name: .kBluetoothStateNotification, object: nil)
    }
    
    open override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        removeTimer()
        NotificationCenter.default.removeObserver(self)

    }
    
    open override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
    }
    
    open func navigationBar() {
        
        let color = type.tintColor
        self.navigation.bar.tintColor = .white
        self.navigation.bar.barTintColor = color
        self.navigation.bar.barStyle = .default
        self.navigation.bar.titleTextAttributes = [.foregroundColor: UIColor.white]
        
        self.navigation.item.title = type.title
        
        self.navigation.item.leftBarButtonItem = UIBarButtonItem(image: UIImage(named: "ic_nav_close_w"), style: .plain, target: self, action: #selector(backAction))
        
        
    }
    
    open override func makeUI() {
        super.makeUI()
        
        self.view.backgroundColor = .white
    
        willStartView.startBtn.backgroundColor = type.tintColor
        willStartView.goalSetBtn.addTarget(self, action: #selector(gotoSetGoal), for: .touchUpInside)
        willStartView.startBtn.addTarget(self, action: #selector(startRun), for: .touchUpInside)
        initMapView()
        
        infoView.tap.subscribe(onNext: {[weak self] in
            
            guard let self = self else { return }
            
            switch $0 {
                
            case .pause:
                self.clickedPause()
                break
            case .locked:
                break
            case .training:
                self.clickedContinue()
                break
            case .endTraining:
                self.clickedEnd()
                break
            }
            
        }).disposed(by: rx.disposeBag)
        
        infoView.isHidden = true
        
        view.addSubview(mapView)
        view.addSubview(gpsSignalView)
        view.addSubview(willStartView)
        view.addSubview(infoView)
        
        mapView.snp.makeConstraints { make in
            make.top.equalToSuperview()
            make.bottom.equalTo(willStartView.snp.top)
            make.left.right.equalToSuperview()
        }
        
        gpsSignalView.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(20)
            make.left.equalToSuperview().offset(20)
            make.width.equalTo(100)
            make.height.equalTo(24)
        }
        
        willStartView.snp.makeConstraints { make in
            make.height.equalTo(100)
            make.left.right.equalToSuperview()
            if #available(iOS 11.0, *) {
                make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom)
            } else {
                make.bottom.equalToSuperview()
            }
        }
        
        infoView.snp.makeConstraints { make in
            make.height.equalTo(260)
            make.left.right.equalToSuperview()
            if #available(iOS 11.0, *) {
                make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom)
            } else {
                make.bottom.equalToSuperview()
            }
        }
    
        self.reloadUIWithTrainingState()
    #if DEBUG
        //TODO: - 测试包用于查看戒指连接状态
        self.view.addSubview(self.bleStateLabel)
        self.bleStateLabel.snp.makeConstraints { make in
            make.trailing.equalTo(-10)
            make.top.equalTo(60)
            make.height.equalTo(20)
            make.leading.equalTo(10)
        }
        self.showBleState(state: BluetoothManager.shared.bluetoothState)
        
        self.view.addSubview(self.connectStateLabel)
        self.connectStateLabel.snp.makeConstraints { make in
            make.trailing.equalTo(-10)
            make.top.equalTo(self.bleStateLabel.snp.bottom).offset(10)
            make.height.equalTo(20)
            make.leading.equalTo(10)
        }
        self.showDeviceState(state: BluetoothManager.shared.deviceState)
    #endif
        
    }
    
    //MARK: - 点击事件
    open override func backAction() {
        
        // 发送结束指令
        BluetoothManager.shared.setTraining(state: .end, type: self.gpsGoalType.goalType, goal: Int(self.gpsGoal))
        guard self.gpsTrainModel != nil else {
            for controller in self.navigationController!.viewControllers where controller is TrainingTypeListController {
                self.gpsTrainModel?.delete()
                self.removeTimer()
                self.navigationController?.popToViewController(controller, animated: true)
                return
            }
            return
        }
        self.gpsTrainModel?.delete()
        self.removeTimer()
        self.navigationController?.popToRootViewController(animated: true)
    }
    
    private func clickedPause() {
        BluetoothManager.shared.setTraining(state: .pause, type: .none, goal: Int(self.gpsGoal))
        self.removeTimer()
        self.updateTrainingState(2)
    }
    
    private func clickedContinue() {
        BluetoothManager.shared.setTraining(state: .proceed, type: self.gpsGoalType.goalType, goal: Int(self.gpsGoal))
        self.updateTrainingState(1)
        self.addTimer()
    }
    
    private func reloadUIWithTrainingState() {
        guard let gpsTrainModel = self.gpsTrainModel else {
            return
        }
        switch gpsTrainModel.trainingState {
        case 0:
            break
        case 1:
            self.gotoMapView()
            break
        case 2:
            self.gotoMapView()
            self.infoView.trainingActionPublishSubject.onNext(.pause)
            self.clickedPause()

            infoModel.updateData(type: .time, currentData: Double(runTime))
            
            if let gpsTrainModel = self.gpsTrainModel {
                
                gpsTrainModel.vaildTime = runTime
                
                let mDistance = Double(gpsTrainModel.totalDistance())
                // 更新距离
                infoModel.updateData(type: .distance, currentData: mDistance)
                
                var speed: Double = 0
                speed = gpsTrainModel.getSpeed()
                // 更新速度（更新配速）
                infoModel.updateSpeed(speed)
                infoModel.updateData(type: .step, currentData: Double(gpsTrainModel.step))
                infoModel.updateData(type: .calorie, currentData: Double(gpsTrainModel.kcal))
                gpsTrainModel.distance = Int(mDistance)
                
                gpsTrainModel.updateData()
            }
            
            infoView.reloadData()
            
            
            break

        default:
            break

        }
    }
    
    private func updateTrainingState(_ state: Int) {
        guard let gpsTrainModel = self.gpsTrainModel else {
            return
        }
        gpsTrainModel.trainingState = state
        gpsTrainModel.updateData()
    }
    
    /// 这个方法是用于运动中断连，然后重连后获取了数据同步到数据库，然后需要更新当前页面的运动数据
    public func reloadTrainingModel() {
        guard let gpsTrainModel = self.gpsTrainModel else {
            return
        }
        self.gpsTrainModel = GPSTrainingModel.model(of: gpsTrainModel.type, startTime: gpsTrainModel.startTime)
        
        if self.gpsTrainModel?.trainingState == 0 && self.gpsTrainModel?.endTime != 0 {
            pushToDetailController()
            return
        }
    }
    
    private func showAlertWhenConnected() {
        if self.isDisconnected == false {
            UIAlertController.showAlertOk(title: "", message: "dialog_training_disconnected_may_inaccurate_data".language, in: self)
            self.isDisconnected = true
        }
    }

    
    //MARK: 定时器
    open func addTimer() {
        if self.time == nil, self.gpsTrainModel?.trainingState == 1 {
            self.time = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: {[weak self] _ in
                guard let self = self else { return }
                self.updateInfo()
            })
            RunLoop.current.add(time!, forMode: .common)
        }
    }
    
    open func removeTimer() {
        if self.time != nil {
            self.time?.invalidate()
            self.time = nil
        }
    }
    
    
    open func initMapView() {
        gpsButton = makeGPSButtonView()
//        let height = UIScreen.main.bounds.height - 100 + 20
       
        mapView.delegate = self
        mapView.mapType = .standard
        mapView.showsCompass = true
        mapView.showsUserLocation = true
        mapView.isRotateEnabled = true
        mapView.setUserTrackingMode(.follow, animated: true)
        //设置地图比例
        let location = mapView.userLocation
        let region = MKCoordinateRegion(center: location.coordinate, latitudinalMeters: CLLocationDistance(exactly: 500)!, longitudinalMeters: CLLocationDistance(exactly: 500)!)
        mapView.region = region
        mapView.setRegion(mapView.regionThatFits(region), animated: false)
        
        mapView.addSubview(gpsButton)
        gpsButton.translatesAutoresizingMaskIntoConstraints = false
        gpsButton.snp.makeConstraints { make in
            make.left.equalToSuperview().offset(20)
            make.bottom.equalToSuperview().offset(-30)
        }
        setUpLocation()
            
    }
    
    open func setGPSSignal(){
        var level = 0
        if gpsAccuracy > 0{
            if gpsAccuracy > GPSSignalLevel1{
                level = 1
            }else if gpsAccuracy > GPSSignalLevel2{
                level = 2
            }else if gpsAccuracy > GPSSignalLevel3{
                level = 3
            }else if gpsAccuracy > GPSSignalLevel4{
                level = 4
            }else {
                level = 5
            }
        }
        gpsSignalView.currentAccuracyLevel = level
    }
    
    open func startLocation() {
        mapView.showsUserLocation = true
        mapView.userTrackingMode = .follow
       
        if gpsTrainModel == nil {
            
            gpsTrainModel = GPSTrainingModel()
            gpsTrainModel?.adress = DeviceInfo.current().adress ?? ""
            gpsTrainModel?.startTime = Int(Date().timeIntervalSince1970)
            gpsTrainModel?.isChina = self.isChina
            gpsTrainModel?.type = self.type.rawValue
            
            gpsTrainModel?.goalType = gpsGoalType.goalType.rawValue
            gpsTrainModel?.goal = Int(gpsGoal)
            if self.LMLocal != nil {
                self.addLocation(location: self.LMLocal)
            }
            gpsTrainModel?.trainingState = 1
            
            gpsTrainModel?.updateData()
        }
//        self.runTime = self.gpsTrainModel?.vaildTime ?? 0
        self.updateTrainingState(self.gpsTrainModel?.trainingState ?? 1)
        self.addTimer()
    }
    
    @objc open func clickedEnd() {
        
        log.debug("actionRecordEnd")
        log.debug("gpsTrainModel =\(String(describing: self.gpsTrainModel?.locations))")
        saveInfo()
        
        if self.runTime < 60 {
            UIAlertController.showEndTraining(title: "training_end_less_than_dialog_title".language, message: "", in: self) { alertAction in
                self.backAction()
            }

            return
        }
        
        guard let gpsTrainModel = gpsTrainModel else {
            
            UIAlertController.showEndTraining(title: "training_little_data_dialog_title".language, message: "", in: self) { action in
                self.backAction()
            }
            return
        }
        
        if self.isDisconnected == true {
            UIAlertController.showOkAlert(title: "dialog_ble_disconnected_when_stop_content".language, message: "", in: self) { [weak self] in
                guard let self = self else { return }
                
                self.updateTrainingState(0)
                self.removeTimer()
                self.saveGPSDataInEnd()
                
                // 发送结束指令
                BluetoothManager.shared.setTraining(state: .end, type: self.gpsGoalType.goalType, goal: Int(self.gpsGoal))

                BluetoothManager.shared.getTrainingtRecordList()
                self.pushToDetailController()
            }
            return
        }
        
        var hasStep = true
        // 有步数的，步数数据 > 0
        if self.type.contents.contains(.step), gpsTrainModel.step <= 0 {
            hasStep = false
        }
        
        if self.isDisconnected == false {
            if gpsTrainModel.kcal <= 0 || hasStep == false || gpsTrainModel.locations.count < 2 {
                UIAlertController.showEndTraining(title: "training_little_data_dialog_title".language, message: "", in: self) { action in
                    self.backAction()
                }
                return
            }
        }
        
        self.updateTrainingState(0)
        self.removeTimer()
        self.saveGPSDataInEnd()
        
        // 发送结束指令
        BluetoothManager.shared.setTraining(state: .end, type: self.gpsGoalType.goalType, goal: Int(self.gpsGoal))

        BluetoothManager.shared.getTrainingtRecordList()
        self.pushToDetailController()
        
    }

    /// 去详情页面
    open func pushToDetailController() {
        
        guard let oldTrainingModel = gpsTrainModel, let gpsTrainModel = TrainingModel.model(of: type.rawValue, startTime: oldTrainingModel.startTime) else {
            return
        }

        // 去详情界面
        let vc = GPSTrainingRecordTableViewController()
        vc.type = type
        
        vc.gpsModel = gpsTrainModel
        vc.achievement = gpsTrainModel.achievement
        vc.isfromMapView = true
        
        navigationController?.pushViewController(vc, animated: true)
        
    }
    
    open func addLocation(location: CLLocation?) {
        if let currentLocal = location{
            let currentHorizontalAccuracy = currentLocal.horizontalAccuracy
            //TODO: 单元测试
//            if currentHorizontalAccuracy > 0 {
            if  currentHorizontalAccuracy <= GPSHorizontalAccuracy && currentHorizontalAccuracy > 0 {
                
                if let success = gpsTrainModel?.addLocation(location: location), success == true {
                    
                    self.coordinateArray.append(currentLocal.coordinate.GCJLocationCoordinate())

                    updatePath()
                }
            }
        }
    }
    
    
    /// 结束时候保存数据
    open func saveGPSDataInEnd() {
        
        guard let gpsTrainModel = gpsTrainModel else {
            return
        }

        gpsTrainModel.endTime = Int(Date().timeIntervalSince1970)
        /// 计算爬升高度
        gpsTrainModel.elevation = gpsTrainModel.calculateElevation(locations: gpsTrainModel.locations)
        
        // 目标达成
        gpsTrainModel.achievement = gpsTrainModel.reloadAchievement(with: gpsGoalType, goal: gpsGoal)

        gpsTrainModel.updateData()
        
    }
    
    open func actionLocation(sender: UIButton) {
        print("actionLocation")
        
        if mapView.userTrackingMode == .follow {
            
            mapView.setUserTrackingMode(.none, animated: false)
            mapView.showsUserLocation = false
        }
        else {
            mapView.setUserTrackingMode(.follow, animated: true)
        }
    }
    
    open func setUpLocation(){
        //CoreLocation
        locationManager.delegate = self
        //设置定位进度
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        //更新距离
        locationManager.distanceFilter = GPSTrainingModel.distanceFilter
        ////发送授权申请
        locationManager.pausesLocationUpdatesAutomatically = false
        locationManager.requestAlwaysAuthorization()
        locationManager.allowsBackgroundLocationUpdates = true
        setupStartUpdate()
    }
    
    open func setupStartUpdate(){
        if !currentEnableLocation{
            if (CLLocationManager.locationServicesEnabled())
            {
                switch CLLocationManager.authorizationStatus() {
                case .notDetermined, .restricted:
                    
                    break
                case .denied:
                    turnOnLocation()
                    break
                    
                case .authorizedAlways, .authorizedWhenInUse:
                    log.debug("Access")
                    //允许使用定位服务的话，开启定位服务更新
                    currentEnableLocation = true
                    locationManager.startUpdatingLocation()
                    locationManager.startUpdatingHeading()
                @unknown default:
                    fatalError()
                }
            }
        }
    }
    
    open func turnOnLocation() {
        if let vc = UIViewController.currentViewController() {
            
            UIAlertController.showPermissionSetting(title: "dialog_gps_training_not_turn_on_location_title".language, message: "", in: vc) { action in
                if let url = URL(string: UIApplication.openSettingsURLString) {
                    if UIApplication.shared.canOpenURL(url) {
                        UIApplication.shared.open(url, options: [:], completionHandler: nil)
                    }
                }
            } cancel: {
                
            }
        }
    }
    
    open func makeGPSButtonView() -> UIButton! {
        let local = UIButton.init(frame: CGRect.init(x: 0, y: 0, width: 40, height: 40))
        local.backgroundColor = UIColor.clear
        
        local.setImage(UIImage.init(named: "btnLocationH"), for: UIControl.State.normal)
        local.addTarget(self, action: #selector(self.gpsAction), for: UIControl.Event.touchUpInside)
        
        return local
    }
    
    @objc open func gpsAction() {
        if(self.mapView.userLocation.isUpdating && self.mapView.userLocation.location != nil) {
            self.mapView.setCenter(self.mapView.userLocation.location!.coordinate, animated: true)
            self.gpsButton.isSelected = true
        }
    }
    
    open func updatePath() {
        let overlays = self.mapView.overlays
        self.mapView.removeOverlays(overlays)
        
        let polyline = MKPolyline(coordinates: &self.coordinateArray, count: Int(UInt(self.coordinateArray.count)))
        self.mapView.addOverlay(polyline)
        
        let lastCoord = self.coordinateArray[self.coordinateArray.count - 1]
        self.mapView.centerCoordinate = lastCoord
    }
    
    @objc open func gotoSetGoal() {
        
        let vc = TrainingGoalSettingController()
        vc.type = type
        vc.delegate = self
        
        self.navigationController?.pushViewController(vc, animated: true)
    }
    
    open func setGoal(type: TrainingTypeContent, index: Int,goal: Double) {
        
        gpsGoal(type: type, goal: goal)
        
        gpsTrainModel?.goalType = gpsGoalType.goalType.rawValue
        gpsTrainModel?.goal = Int(gpsGoal)
        gpsTrainModel?.updateData()
        
        startRun()
        
    }
    
    open func gpsGoal(type: TrainingTypeContent, goal: Double) {
        
        self.gpsGoalType = type
        
        switch type {
        case .distance:
            self.gpsGoal = goal
            break
        default:
            self.gpsGoal = goal
            break
            
        }
    }
   
    @objc open func startRun(){
        let state = CLLocationManager.authorizationStatus()
        if state == .authorizedAlways || state == .authorizedWhenInUse {
            if  gpsAccuracy > GPSHorizontalAccuracy {
                let alertController = UIAlertController(title: "", message: "gps_training_gps_weak_signal".language, preferredStyle: .alert)
                let cancelAction = UIAlertAction(title: "dialog_cancel".language, style: .cancel, handler: nil)
                let continueAction = UIAlertAction(title: "gps_training_continue".language, style: .default, handler: {  [weak self] action in
                    guard let `self` = self else {
                        return
                    }
                    self.showCountDownView()
                    
                })
                alertController.addAction(cancelAction)
                alertController.addAction(continueAction)
                self.present(alertController, animated: true, completion: nil)
            } else {
                self.showCountDownView()
            }
        }else {
            let alertController = UIAlertController(title: "", message: "gps_training_enable_gps_hint".language, preferredStyle: .alert)
            let cancelAction = UIAlertAction(title: "dialog_cancel".language, style: .cancel, handler: nil)
            let settingAction = UIAlertAction(title: "dialog_gps_training_not_turn_on_location_go_setting".language, style: UIAlertAction.Style.default, handler: { (action) in
                let url = URL(string: UIApplication.openSettingsURLString);
                
                if UIApplication.shared.canOpenURL(url!) {
                    if #available(iOS 10.0, *) {
                        UIApplication.shared.open(url!)
                        
                    } else {
                        UIApplication.shared.openURL(url!)
                    }
                }
            })
            alertController.addAction(cancelAction)
            alertController.addAction(settingAction)
            self.present(alertController, animated: true, completion: nil)
            
        }
    }
    
    /// 设备设置 运动模式
    open func setDiviceTrainingType() {
        
        guard let type = type.CPRTrainningType else { return }
        BluetoothManager.shared.setTraining(state: type, type: gpsGoalType.goalType, goal: Int(gpsGoal))
       
        
    }
    
    @objc open func showCountDownView(){
        setupStartUpdate()
        setCountDownAnimation()
        
        
        setDiviceTrainingType()
        
        countDownView.play(number: 3, endTitle: "GO!") { [weak self] in
            self?.countDownBGView.removeFromSuperview()
            
            self?.gotoMapView()
        }
    }
    
    @objc open func gotoMapView(){
        let type = gpsGoalType//gpsGoalType == .unkown ? TrainingTypeContent.distance : gpsGoalType
        let gpsGoal = self.gpsGoal > 0 ? self.gpsGoal : nil
        
        infoModel = GPSTrainingInfoModel(type: type, goal: gpsGoal)
        
        infoView.type = self.type
        infoView.infoModel = infoModel
        infoView.reloadData()
        
        if !barViewHidden {
            
            mapView.snp.remakeConstraints { make in
                make.top.equalToSuperview()
                make.bottom.equalTo(infoView.snp.top)
                make.left.right.equalToSuperview()
            }
            
            gpsSignalView.snp.remakeConstraints { make in
                make.top.equalToSuperview().offset(50)
                make.left.equalToSuperview().offset(20)
                make.width.equalTo(100)
                make.height.equalTo(24)
            }
            
            barViewHidden = true
            willStartView.isHidden = true
            infoView.isHidden = false
            
            startLocation()

        } else {
            
            barViewHidden = false
            willStartView.isHidden = false
            infoView.isHidden = true

        }
        
    }
    

    open func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        let identifier = "User"

        var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)

        if annotationView == nil{
            annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
            annotationView?.canShowCallout = true
        } else {
            annotationView?.annotation = annotation
        }
        
        if let image = UIImage(named: "ic_gps_exercise_map_point"){
            annotationView?.image = image
            self.userAnnotationView = annotationView
            annotationView?.centerOffset = CGPoint(x: 0, y: -image.size.height/3)
        }
        

        return annotationView
    }
    
    open func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        guard let polyline = overlay as? MKPolyline else {
            return MKOverlayRenderer()
        }
        log.debug("polyline = \(polyline)")

        let polylineView = MKPolylineRenderer(overlay: polyline)
        polylineView.lineWidth = 6.0
        polylineView.strokeColor = UIColor(red: 74 / 255.0, green: 144 / 255.0, blue: 226 / 255.0, alpha: 1.0)

        return polylineView
    }
    
    open func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
        log.debug("regio = \(mapView.region.span)")
    }
    

    open func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
        if newHeading.headingAccuracy < 0{
            return
        }else {
            let heading = newHeading.trueHeading > 0 ? newHeading.trueHeading : newHeading.magneticHeading
            let rotation = heading/180 * CGFloat.pi
            self.userAnnotationView?.transform = CGAffineTransform(rotationAngle: CGFloat(rotation))
        }
    }
    
    /// 获取的火星坐标系
    open func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        
        log.debug("CLLocationManager didUpdateLocations.count = \(locations.count)")
        
        for location in locations {
            
            guard let _ = time else { return }
            
            addLocation(location: location)
            
        }

    }
    
  
    //MARK: - 开始运动的倒计时
    open func setCountDownAnimation(){
        countDownBGView = UIView(frame: CGRect(x: 0, y: 0, width: kScreenWidth, height: kScreenHeight))
        countDownBGView.backgroundColor = type.tintColor
        self.view.addSubview(countDownBGView)
        countDownView = CountDownLabel(frame: CGRect(x: 0, y: 0, width: kScreenWidth, height: kScreenHeight))
        countDownBGView.addSubview(countDownView)
        countDownView?.center = countDownBGView.center
        
        countDownView.scale = 0.5
        countDownView.textFont = Fonts.systemFont(ofSize: 120, weight: .medium)
        countDownView.layer.borderWidth = 0
        countDownView.label_maskToBounds = false
        countDownView.countDownType = .countDownBig
    }
    
    
    
    @objc open func updateInfo() {
        let timestamp = Int(Date().timeIntervalSince1970)
        
        if timestamp%60 == 0 {
            saveInfo()
        }
        guard mapView.userLocation.location != nil else {
            return
        }
       
        runTime += 1
        
        infoModel.updateData(type: .time, currentData: Double(runTime))
        
        if let gpsTrainModel = self.gpsTrainModel {
            
            gpsTrainModel.vaildTime = runTime
            
            let mDistance = Double(gpsTrainModel.totalDistance())
            // 更新距离
            infoModel.updateData(type: .distance, currentData: mDistance)
            
            var speed: Double = 0
            speed = gpsTrainModel.getSpeed()
            // 更新速度（更新配速）
            infoModel.updateSpeed(speed)
            

            gpsTrainModel.distance = Int(mDistance)
            
            gpsTrainModel.updateData()
        }
        
        infoView.reloadData()
        
    }
    
    open func saveInfo(){
        var pastMinSteps = Int(gpsTrainModel?.step ?? 0) - pastSteps
        var pastMinDistance = Int((gpsTrainModel?.totalDistance() ?? 0.0) - pastDistance)
        if pastMinSteps <= 0 {
            pastMinSteps = 0
        }
        if pastMinDistance <= 0 {
            pastMinDistance = 0
        }
        gpsTrainModel?.distances.append(pastMinDistance)
        gpsTrainModel?.steps.append(Int(pastMinSteps))
        
        pastDistance = (gpsTrainModel?.totalDistance() ?? 0.0)
        pastSteps = Int(gpsTrainModel?.step ?? 0)
    }
    
    //MARK: - 通知响应 -
    
    @objc open func updateUI(noti: Notification) {
        
        guard let dict = noti.userInfo as? [String: Any], let type = dict["type"] as? NotifactionType else { return }
        
        switch type {
       
        case .activity:
            
            updateStepAndKcal(noti: noti)
            break
            
        case .realTimeHeartRate:
            
            updateHeart(noti: noti)

            break
        case .sportState:
            
//            sportStateChange(noti: noti)
            
            break
            
        case .sportList:
            
            log.debug("GPS 收到 锻炼列表")
            log.debug("trainAction = \(self.gpsTrainModel?.trainingState)")
            log.debug("currentTraining.state = \(BluetoothResponder.shared.currentTraining?.state.rawValue)")
            
            
//            if self.trainingState != .unstarted {
//                return
//            }
//
//            pushToDetailController()
            
            break
            
        default:
            break
            
        }
        
    }
    
    @objc open func updateHeart(noti: Notification) {
        
        guard let dict = noti.userInfo as? [String: Any], let model = dict["result"] as? ReceiveRealTimeHeartRateModel else {
            return
        }
        
        let heartRate = model.heartRate
        if self.gpsTrainModel?.trainingState != 1 {
            return
        }
        
        // UI 显示
        if(heartRate == 255) {
            infoModel.updateData(type: .heartRate, currentData: 0)
        } else {
    
            infoModel.updateData(type: .heartRate, currentData: Double(heartRate))
            infoView.reloadData()
            
            /// 心率预警弹窗
            BluetoothResponder.shared.heartRateMaxAlert(model.heartRate)
            
        }
        
        // 数据库更新
        guard let trainingModel = gpsTrainModel else { return }
        
        let nowTime = Date().timeIntervalSince1970
        let interval = nowTime - trainingModel.heartRatesUpdateTime
        
        // 每10秒截取一个心率
        if interval >= 10 {
            trainingModel.heartRates.append(heartRate)
            
            // 计算平均心率
            var avgHeart = 0
            var totalHeart = 0
            var heartCount = 0
            for heart in trainingModel.heartRates {
                if heart > 0 {
                    totalHeart += heart
                    heartCount += 1
                }
            }
            if heartCount > 0 {
                avgHeart = totalHeart/heartCount
            }
            
            trainingModel.heartRateAvg = avgHeart
            trainingModel.heartRatesUpdateTime = nowTime
            trainingModel.updateData()
            
        }
        
    }
    
    @objc open func updateStepAndKcal(noti: Notification) {
        
        if self.gpsTrainModel?.trainingState != 1 {
            return
        }
        
        guard let gpsTrainModel = gpsTrainModel else {
            return
        }
        
        
        guard let activityModel = ActivityModel.day(date: Date()) else {
            return
        }
                
        guard activityModel.step >= startDetail.step else {
            return
        }
        
        guard activityModel.calorie >= startDetail.calorie else {
            return
        }
        
        gpsTrainModel.step = Int(activityModel.step - startDetail.step) + gpsTrainModel.step
        let kcal = Int(activityModel.calorie - startDetail.calorie) + gpsTrainModel.kcal
        gpsTrainModel.kcal = kcal
        gpsTrainModel.updateData()
        
        startDetail = activityModel
        
        infoModel.updateData(type: .calorie, currentData: Double(kcal))
        infoView.reloadData()
        
    }
    
    @objc open func deviceStateChange(noti: Notification) {
        guard let result = noti.userInfo as? [String: Any] else { return }
        guard let state = result["result"] as? CRPState else { return }
        
        self.showDeviceState(state: state)
        
        guard state == .connected else {
            self.showAlertWhenConnected()
            return
        }
        self.isDisconnected = false
    }
    
    @objc open func bluetoothStateChange(noti: Notification) {
        guard let result = noti.userInfo as? [String: Any] else { return}
        guard let state = result["result"] as? CRPBluetoothState else { return }
        
        self.showBleState(state: state)
        
        guard state == .poweredOn else {
            self.showAlertWhenConnected()
            return
        }
    }
    
    // TODO: - 测试用
    private func showBleState(state: CRPSmartRing.CRPBluetoothState) {
        switch state{
        case .poweredOn:
            self.bleStateLabel.text = "蓝牙已打开"
        case .poweredOff:
            self.bleStateLabel.text = "ble_disable".language
            self.connectStateLabel.text = "ble_disconnected".language
        default:
            self.bleStateLabel.text = "蓝牙已打开".language
        }
    }
    
    private func showDeviceState(state: CRPSmartRing.CRPState) {
        switch state{
        case .connected:
            self.connectStateLabel.text = "ble_connected".language
        case .disconnected:
            self.connectStateLabel.text = "ble_disconnected".language
        case .connecting:
            self.connectStateLabel.text = "ble_connecting".language
        default:
            self.connectStateLabel.text = "ble_connecting".language
        }
    }
    
    //MARK: - lazy load -
    private lazy var bleStateLabel: Label = {
        let label = Label()
        label.font = .systemFont(ofSize: 14)
        label.textColor = UIColor.theme
        label.textAlignment = .right
        return label
    }()
    
    private lazy var connectStateLabel: Label = {
        let label = Label()
        label.font = .systemFont(ofSize: 14)
        label.textColor = .init(hex: "FF2E29")
        label.textAlignment = .right
        return label
    }()
    

//    @objc func sportStateChange(noti: Notification) {
//
//        guard let dict = noti.userInfo as? [String: Any], let type = dict["result"] as? CRPSmartRing.CRPTrainingType else { return }
//
//        switch type {
//        case .pause:
//
//            self.removeTimer()
//            self.trainingState = .pause
//
//        case .proceed:
//
//            self.trainingState = .exercising
//            self.addTimer()
//
//        case .end:
//
//            self.trainingState = .unstarted
//            // 同步 列表指令
//            BluetoothManager.shared.getTrainingtRecordList()
//
//
//        default:
//            break
//        }
//
//    }
    

}


extension GPSTrainingMapViewController {
    
    open class GPSSignalView: UIView {
        
        public let defaultColor: UIColor = UIColor.theme
        public let signalNormalColor: UIColor = UIColor.assist_EEEEEE
        
        public let titleLabel: UILabel = {
            let lbl = UILabel()
            lbl.textColor = .black
            lbl.font = .systemFont(ofSize: 12)
            lbl.textAlignment = .left
            lbl.text = "GPS:"
            return lbl
        }()
        
        public var signalViews: [UIView] = []
        open var currentAccuracyLevel:Int = -1 {
            didSet{
                if currentAccuracyLevel != oldValue{
                    if signalViews.count == 5 && currentAccuracyLevel > 0{
                        var signalCount = 0
                        switch currentAccuracyLevel{
                        case 1:
                            signalCount = 0
                            signalViews.first?.backgroundColor = UIColor.theme
                        case 2:
                            signalCount = 2
                        case 3:
                            signalCount = 3
                        case 4:
                            signalCount = 4
                        case 5:
                            signalCount = 5
                        default:
                            break
                        }
                        if signalCount > 0 && signalCount <= 5{
                            for i in 0..<signalCount{
                                signalViews[i].backgroundColor = signalNormalColor
                            }
                        }
                        let defaultCount = 5 - signalCount
                        if defaultCount > 0{
                            for i in signalCount..<5{
                                signalViews[i].backgroundColor = defaultColor
                            }
                        }
                    }
                }
            }
        }
        public override init(frame: CGRect) {
            super.init(frame: frame)
            makeUI()
        }
        
        public required init(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        open func makeUI(){
            self.backgroundColor = .white
            self.layer.cornerRadius = 12
            self.addSubview(titleLabel)
            titleLabel.snp.makeConstraints { make in
                make.left.equalTo(12)
                make.centerY.equalToSuperview()
            }
            
            signalViews = []
            let signalStackView = UIStackView()
            signalStackView.distribution = .fillEqually
            signalStackView.axis = .horizontal
            signalStackView.alignment = .fill
            signalStackView.spacing = 6
            for _ in 0..<5{
                let barView = UIView()
                barView.backgroundColor = defaultColor
                signalViews.append(barView)
                signalStackView.addArrangedSubview(barView)
            }
            
            self.addSubview(signalStackView)
            signalStackView.snp.makeConstraints { make in
                make.left.equalTo(titleLabel.snp.right).offset(6)
                make.centerY.equalToSuperview()
                make.width.equalTo(44)
                make.height.equalTo(10)
            }
        }
    }
    
}
